﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace NumericalMethod
{
   public partial class InterpolationForm : ContentPane
   {
      private StatusForm mStatus;
      private VParser FormulaParser = new VParser();//= new Parser();
      private graphFX graph;
      private int ActiveMethod;
      private bool fxMode = true;
      const string separator = "==================================";


      public InterpolationForm()
      {
         InitializeComponent();
      }

      private void methodComboBox_SelectedIndexChanged(object sender, EventArgs e)
      {
         ActiveMethod = methodComboBox.SelectedIndex;
         enableDisable();
      }
      public override void OnLoad()
      {
         mStatus = new StatusForm();
         Parent.Controls.Add(mStatus);
         graph = new graphFX();
         Parent.Controls.Add(graph);
         methodComboBox.SelectedIndex = 0;
         mStatus.HidePanel(2);
      }
      private void enableDisable()
      {
         label3.Enabled = fxMode;
         equationText.Enabled = fxMode;

         fx0Text.Enabled = label4.Enabled = (ActiveMethod >= 0 && !fxMode);
         fx1Text.Enabled = label5.Enabled = (ActiveMethod >= 0 && !fxMode);
         fx2Text.Enabled = label6.Enabled = (ActiveMethod >= 1 && !fxMode);
         fx3Text.Enabled = label7.Enabled = (ActiveMethod == 2 && !fxMode);

         x0Text.Enabled = label2.Enabled = (ActiveMethod >= 0);
      }
      private void radioButton3_CheckedChanged(object sender, EventArgs e)
      {
         fxMode = fxEqMode.Checked;
         enableDisable();
      }

      private void button1_Click(object sender, EventArgs e)
      {
         graph.PointsList.Clear();
         //graph.BackPointsList.Clear();
         graph.PlotTitle = (method1.Checked)?method1.Text:method2.Text;

         if (fxMode)
         {
            double pResult;
            double x0 = (double)x0Text.DecimalValue;
            for (double x = 0; x < 50; x++)
            {
               string formula = equationText.Text.Replace("x", x0.ToString());
               pResult = FormulaParser.Parse(formula);
               graph.PointsList.Add(x0, pResult);
               x0 += (double)hText.DecimalValue / 50;
            }
            graph.CreateLineGraph();
         }
         else
         {
            if (ActiveMethod == 0)
            {
               mStatus.AppendOutput(separator);
               mStatus.AppendOutput("Linear Interpolation");
               double[] x = new double[] { x0Text.DoubleValue, x0Text.DoubleValue + hText.DoubleValue };
               double[] fx = new double[] { fx0Text.DoubleValue, fx1Text.DoubleValue };
               graph.PointsList.Add(x0Text.DoubleValue, fx0Text.DoubleValue);
               graph.PointsList.Add(x0Text.DoubleValue + hText.DoubleValue, fx1Text.DoubleValue);
               if (!string.IsNullOrEmpty(xText.Text))
               {
                  double ans = methodSelect(x, fx, 2, xText.DoubleValue);
                  mStatus.AppendOutput("Given f(" + xText.Text + ") : " + ans);
                  answer.Text = ans + "";
               }

               double x0 = x0Text.DoubleValue;
               double ln = Math.Abs(hText.DoubleValue);

               for (double i = 0; i < 50; i++)
               {
                  graph.PointsList.Add(i, methodSelect(x, fx, 2, i));
                  x0 += ln / 50;
               }
               graph.AddLineOnly();
            }
            else if (ActiveMethod == 1)
            {
               mStatus.AppendOutput(separator);
               mStatus.AppendOutput("Quadratic Interpolation");
               double[] x = new double[] { x0Text.DoubleValue, x0Text.DoubleValue + hText.DoubleValue,
                  x0Text.DoubleValue+hText.DoubleValue*2 };
               double[] fx = new double[] { fx0Text.DoubleValue, fx1Text.DoubleValue, fx2Text.DoubleValue };
               graph.PointsList.Add(x0Text.DoubleValue, fx0Text.DoubleValue);
               graph.PointsList.Add(x0Text.DoubleValue + hText.DoubleValue, fx1Text.DoubleValue);
               graph.PointsList.Add(x0Text.DoubleValue + hText.DoubleValue * 2, fx2Text.DoubleValue);
               if (!string.IsNullOrEmpty(xText.Text))
               {
                  double ans = methodSelect(x, fx, 3, xText.DoubleValue);
                  mStatus.AppendOutput("Given f(" + xText.Text + ") : " + ans);
                  answer.Text = ans + "";
               }

               double x0 = x0Text.DoubleValue;
               double ln = Math.Abs((x0Text.DoubleValue + hText.DoubleValue*2) - x0Text.DoubleValue);

               for (double i = 0; i < 50; i++)
               {
                  graph.PointsList.Add(i, methodSelect(x, fx, 3, i));
                  x0 += ln / 50;
               }
               graph.AddLineOnly();
            }
            else if (ActiveMethod == 2)
            {
               mStatus.AppendOutput(separator);
               mStatus.AppendOutput("Cubic Interpolation");
               double[] x = new double[] { x0Text.DoubleValue, x0Text.DoubleValue+hText.DoubleValue, 
               x0Text.DoubleValue+hText.DoubleValue*2,
               x0Text.DoubleValue+hText.DoubleValue*3};
               double[] fx = new double[] { fx0Text.DoubleValue, fx1Text.DoubleValue, fx2Text.DoubleValue, fx3Text.DoubleValue };
               graph.PointsList.Add(x0Text.DoubleValue, fx0Text.DoubleValue);
               graph.PointsList.Add(x0Text.DoubleValue + hText.DoubleValue, fx1Text.DoubleValue);
               graph.PointsList.Add(x0Text.DoubleValue + hText.DoubleValue * 2, fx2Text.DoubleValue);
               graph.PointsList.Add(x0Text.DoubleValue + hText.DoubleValue * 3, fx3Text.DoubleValue);
               if (!string.IsNullOrEmpty(xText.Text))
               {
                  double ans = methodSelect(x, fx, 4, xText.DoubleValue);
                  mStatus.AppendOutput("Given f(" + xText.Text + ") : "+ans);
                  answer.Text = ans+"";
               }
               double x0 = x0Text.DoubleValue;
               double ln = Math.Abs((x0Text.DoubleValue + hText.DoubleValue*2) - x0Text.DoubleValue);
               for (double i = 0; i < 50; i++)
               {
                  graph.PointsList.Add(x0, methodSelect(x, fx, 3, x0));
                  x0 += ln / 50;
               }
               graph.AddLineOnly();
            }
         }
      }
      private double methodSelect(double[] x, double[] f, int n, double t)
      {
         if (method1.Checked)
            return NewtonInterpolator(x, f, n, t);
         else
            return NevilleInterpolator(x, f, n, t);
      }
      public double NewtonInterpolator(double[] x, double[] f, int n, double t)
      {
         double F, LN, XX, X = 1;
         int i, j, k;
         for (i = 1, LN = f[0]; i < n; i++)
         {
            X *= (t - x[i - 1]);
            for (j = 0, F = 0; j <= i; j++)
            {
               for (k = 0, XX = 1; k <= i; k++)
               {
                  if (k != j)
                     XX *= x[j] - x[k];
               }
               F += f[j] / XX;
            }
            LN += X * F;
         }
         return LN;
      }
      public double NevilleInterpolator(double[] x, double[] f, int n, double t)
      {
         int m = 0;
         int i = 0;

         f = (double[])f.Clone();

         n = n - 1;
         for (m = 1; m <= n; m++)
         {
            for (i = 0; i <= n - m; i++)
            {
               f[i] = ((t - x[i + m]) * f[i] + (x[i] - t) * f[i + 1]) / (x[i] - x[i + m]);
            }
         }
         return f[0];
      }
   }
}
